package 操作系统实验.实验三;/**
 * ************************************************************************
 * 项目名称: projectweb <br>
 * 文件名称:  <br>
 * 文件描述: 这里添加您的类文件描述，说明当前文件要包含的功能。 <br>
 * 文件创建：1913040634刘世锦  <br>
 * 创建时间: 2021/4/15 <br>
 *
 * @version v1.0 <br>
 * @update [序号][日期YYYY-MM-DD][更改人姓名][变更描述]<br>
 * ************************************************************************
 */

/**
 * @ProjectName: projectweb
 * @ClassName: Bank
 * @Description: 请描述该类的功能
 * @Author: 1913040634刘世锦
 * @Date: 2021/4/15 17:41 .
 * @version v1.0
 */

import java.util.*;

/**
 *
 */
public class Bank {
    /**
     * 资源可用数目
     */
    private int[] Available;
    /**
     * 最大需求矩阵
     */
    private int[][] Max;
    /**
     * 已分配矩阵
     */
    private int[][] Alloction;
    /**
     * 需求矩阵
     */
    private int[][] Need;
    /**
     * 进程是否完成矩阵
     */
    private boolean[] Finish;
    /**
     * 进程数组
     */
    private Process[] Processes;

    /**
     * 安全状态进程
     */
    private List<Process> securityProcesses;

    /**
     * 进程请求资源数组
     */
    private int[] request;

    private boolean[] tmp;


    /**
     * 无参构造，需调用初始化函数
     */
    public Bank() {
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        Scanner scanner = new Scanner(System.in);
        //进程初始化，Finish矩阵初始化
        System.out.println("请输入进程个数：");
        int processNum = scanner.nextInt();
        Finish = new boolean[processNum];
        Processes = new Process[processNum];
        System.out.println("请按顺序输入各进程的名称：");
        for (int i = 0; i < Processes.length; i++) {
            String tmpProcessName = scanner.next();
            Processes[i] = new Process(tmpProcessName);
        }

        //资源初始化 Avalibale数组，Allocation矩阵，Max矩阵，Need矩阵
        System.out.println("请输入资源种类数：");
        int resourecNum = scanner.nextInt();
        System.out.println("请输入Avaliable数组：");
        Available = new int[resourecNum];
        for (int i = 0; i < resourecNum; i++) {
            Available[i] = scanner.nextInt();
        }
        System.out.println("请输入Allocation矩阵");
        Alloction = new int[processNum][resourecNum];
        for (int i = 0; i < processNum; i++) {
            for (int j = 0; j < resourecNum; j++) {
                Alloction[i][j] = scanner.nextInt();
            }
        }
        System.out.println("请输入Max矩阵");
        Max = new int[processNum][resourecNum];
        for (int i = 0; i < processNum; i++) {
            for (int j = 0; j < resourecNum; j++) {
                Max[i][j] = scanner.nextInt();
            }
        }
        Need = new int[processNum][resourecNum];
        for (int i = 0; i < processNum; i++) {
            for (int j = 0; j < resourecNum; j++) {
                Need[i][j] = Max[i][j] - Alloction[i][j];
            }
        }
        securityProcesses = new ArrayList<>(Finish.length);
        request = new int[Available.length];
        Finish = new boolean[Finish.length];
        tmp = new boolean[Finish.length];
        System.out.println();
    }

    /** p2 1 2 p2 0 1 p0 3 1
     * 安全性检测
     */
    public boolean securityExamine() {
        /**
         * 工作矩阵，其实就是Avaliable
         */
        int[] Work = new int[Available.length];
        System.arraycopy(Available,0,Work,0, Available.length);
        Finish = new boolean[Finish.length];
        scanfNoNeed(Work);
        for (int i = 0; i<Processes.length ;i++) {
            if(!Finish[i]) {
                boolean tmp = true;
                for (int j = 0; j < Work.length; j++) {
                    if(Need[i][j]>Work[j]) {
                        tmp = false;
                        break;
                    }
                }
                if(tmp) {
                    //满足条件，表示i号进程满足可以分配的情况
                    String proN = null;
                    try {
                        proN = getproN(i);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    //修改i进程的状态位
                    Finish[i] = true;
                    //回收i进程占有的资源
                    for (int j = 0; j < Work.length; j++) {
                        Work[j] = Work[j] + Alloction[i][j];
                    }
                    //把该进程放入安全序列中
                    securityProcesses.add(Processes[i]);
                    //每次从头开始查找是否可以分配
                    i = -1;
                    System.out.println("进程"+proN+"分配成功!     此时Work："+Arrays.toString(Work));
                }
            }
        }
        //全部分配完直接返回
        if(securityProcesses.size() == Finish.length) {
            System.out.println("状态安全");
            System.out.println("安全序列为："+ securityProcesses);
            securityProcesses.clear();
            return true;
        }
        //状态不安全
        System.out.println("状态不安全");
        return false;
    }

    /**
     * 扫描need矩阵，将need全为0的进程优先放入安全序列
     */
    private void scanfNoNeed(int[] Work) {
        for (int i = 0; i < Finish.length; i++) {
            boolean isNeed = true;
            for (int j = 0; j < Work.length; j++) {
                if(Need[i][j] != 0) {
                    isNeed = false;
                    break;
                }
            }
            //满足条件，则i进程need全为0
            if(isNeed) {
                String proN = null;
                try {
                    proN = getproN(i);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                //修改i进程的状态位
                Finish[i] = true;
                //回收i进程占有的资源
                for (int j = 0; j < Work.length; j++) {
                    Work[j] = Work[j] + Alloction[i][j];
                }
                //把该进程放入安全序列中
                securityProcesses.add(Processes[i]);
                System.out.println("进程"+proN+" need为0，直接释放!     此时Work："+Arrays.toString(Work));
            }
        }
    }

    /**
     * 请求资源
     */
    public void request() {
        //输入
        System.out.println("请输入请求资源的进程名称：");
        Scanner scanner = new Scanner(System.in);
        String proN = scanner.nextLine();
        int processNum = 0;
        try {
            processNum = getProceesNum(proN);
        } catch (IllegalAccessException e) {
            System.out.println("进程名称错误，找不到对应进程");
            return;
        }
        System.out.println("请分别输入各进程的请求资源数目：");
        for (int i = 0; i < request.length; i++) {
            request[i] = scanner.nextInt();
        }

        //request<=need
        for (int i = 0; i < request.length; i++) {
            if(request[i] > Need[processNum][i]) {
                System.out.println("request > need，请求参数不合法");
                return;
            }
        }
        //request<=work
        for (int i = 0; i < request.length; i++) {
            if(request[i] > Available[i]) {
                System.out.println("request > work,请求过大，无法分配");
                return;
            }
        }
        //为该进程分配资源
        for (int i = 0; i < request.length; i++) {
            Need[processNum][i] -= request[i];
            Available[i] -= request[i];
            Alloction[processNum][i] += request[i];
        }

        /**
         * 分配完成后，判断该状态是否安全，如果不安全，进行回退
         */
        boolean isSecurity = securityExamine();
        if(!isSecurity) {
            //进程回退
            for (int i = 0; i < request.length; i++) {
                Need[processNum][i] += request[i];
                Available[i] += request[i];
                Alloction[processNum][i] -= request[i];
            }
        } else {
            printState();
        }
    }
    public void printState() {
        System.out.println();
        System.out.println("-------------------------当前进程状态----------------------------");
        System.out.println();
        System.out.println("processes\t\tAllocation\t\tNeed\t\t");
        for (int i = 0; i < Finish.length; i++) {
            String proN = null;
            try {
                proN = getproN(i);
            } catch (IllegalAccessException e) {
                System.out.println("非法的下标");
            }
            System.out.print(proN+"\t\t\t\t");
            for (int j = 0; j < Available.length; j++) {
                System.out.print(Alloction[i][j]+" ");
            }
            System.out.print("\t\t");
            for (int j = 0; j < Available.length; j++) {
                System.out.print(Need[i][j]+" ");
            }
            System.out.println();
        }
        System.out.println("Avalibale:"+Arrays.toString(Available));
    }

    private String getproN(int i) throws IllegalAccessException {
        for (int j = 0; j < Processes.length; j++) {
            if(i == j) {
                return Processes[i].getName();
            }
        }
        throw new IllegalAccessException("非法下标");
    }

    /**
     * 根据进程名称找到对应的第几个进程
     * @param proN 进程名称
     * @return 返回第几个进程
     * @throws IllegalAccessException 非法的名称异常
     */
    private int getProceesNum(String proN) throws IllegalAccessException {
        for (int i = 0; i < Processes.length; i++) {
            if(proN.equals(Processes[i].getName())) {
                return i;
            }
        }
        throw new IllegalAccessException("名字非法");
    }
}


